﻿package Map
{
	import Map.Model.Builder;
	import Component.Map;
	import Map.Block;
	import Component.BonusBlock;
	import Component.BonusBlocks.BonusBlock_Delay;
	import Component.BonusBlocks.BonusBlock_Bomb;
	import Component.BonusBlocks.BonusBlock_Range;
	import Component.BonusBlocks.BonusBlock_Speed;
	import Component.BonusBlocks.BonusBlock_Base;

	public class Zone extends Contexted implements Builder
	{
		// how many block are in the zone
		private var blocks:Vector.<BonusBlock > ;
		// how many bonus of each type you will find in this zone
		private var nb_bonus:uint;
		private var nb_max:int;

		private var drop_chance:uint;

		private var bonuses:Vector.<BonusBlock_Base > ;

		public function Zone(context:Context,nb_bonus:uint)
		{
			super(context);
			this.nb_bonus = nb_bonus;
			blocks = new Vector.<BonusBlock>();

			bonuses = new Vector.<BonusBlock_Base>();
		}

		// call this when all blocks are attached
		public function initialize():void
		{
			//trace("nb bonus : " + nb_bonus);
			computeDropChance();
			nb_max = drop_chance * nb_bonus;
			//trace("nb_max : " + nb_max);

			bonuses.push(new BonusBlock_Base(context.map,0,nb_bonus,nb_max));
			bonuses.push(new BonusBlock_Base(context.map,1,nb_bonus,nb_max));
			bonuses.push(new BonusBlock_Base(context.map,2,nb_bonus,nb_max));
			bonuses.push(new BonusBlock_Base(context.map,3,nb_bonus,nb_max));


			for (var index:int = 0; index < nb_max; index++)
			{
				bonuses[BonusType.SPEED].attach(new BonusBlock_Speed());
				bonuses[BonusType.BOMB].attach(new BonusBlock_Bomb());
				bonuses[BonusType.DELAY].attach(new BonusBlock_Delay());
				bonuses[BonusType.RANGE].attach(new BonusBlock_Range());
			}
		}

		private function computeDropChance():void
		{
			var drop_chance:int = 0;
			var sum_bonus:int = (BonusType.length * nb_bonus);

			// look for non coherent data
			if ( (BonusType.length * nb_bonus) > blocks.length)
			{
				throw new Error("Cant compute Drop Chance");
			}

			// estimate perfect drop chance
			drop_chance = blocks.length / sum_bonus;
			var density:int = computeDensity(drop_chance,nb_bonus);

			// check if density is okay
			if ( (density >= 70) && (density <= 90) )
			{
				this.drop_chance = drop_chance;
			}

			// density is not okay
			// lets find the problem
			var modifier:int;
			if (density < 70)
			{
				modifier = +1;
			}
			else
			{
				modifier = -1;

			}// lets try to modify drop_chance
			density = computeDensity(drop_chance + modifier, nb_bonus);

			// check if density is okay
			if ((density >= 70) && (density <= 90))
			{
				this.drop_chance = (drop_chance + modifier);
			}

			// lets try to modify nb_bonus
			density = computeDensity(drop_chance,nb_bonus + modifier);

			// check if density is okay
			if ((density >= 70) && (density <= 90))
			{
				this.drop_chance = (drop_chance + modifier);
				nb_bonus +=  modifier;
			}
			//trace("Drop chance is : " + drop_chance);
			this.drop_chance = drop_chance;
		}

		private function computeDensity(drop_chance:int, nb_bonus:int):int
		{
			var sum_bonus:int = (BonusType.length * nb_bonus);
			var total_blocks:int = drop_chance * sum_bonus;
			// we have nb_registered > total_blocks
			return (100 * total_blocks / blocks.length);
		}

		public function reset(map:Map):void
		{
			var bonus:BonusBlock_Base;
			//trace("Blocks in the zone : " + nb_max * BonusType.length);
			// we reset every bonuses by type
			for each (bonus in bonuses)
			{
				bonus.reset();
			}

			// we copy the vector of registred blocks
			var blocks_available:Vector.<BonusBlock >  = blocks.slice();
			// we determine all the blocks we will use
			for (var index:int = 0; index < nb_max; index++)
			{
				for each (bonus in bonuses)
				{
					// choose a bonus block
					var block:BonusBlock = pickBlock(blocks_available);
					// retrieve the MovieClip
					block.bonus = bonus.clipAt(index);
					// make it visible
					map.display(block);
				}
			}
		}

		private function pickBlock(blocks:Vector.<BonusBlock >):BonusBlock
		{
			var index:int = context.randomizer.NextUInt(0,blocks.length - 1);
			//trace("Choosen index : " + index);
			var block:BonusBlock = blocks[index];
			blocks.splice(index, 1);
			return block;
		}

		public function createBonusBlock(x:uint,y:uint):BonusBlock
		{
			var block:BonusBlock = new BonusBlock();
			block.initialize(x,y);
			blocks.push(block);
			return block;
		}

	}

}